package com.malex.mxtracker.util;

import com.malex.mxtracker.MxTracker;
import com.malex.mxtracker.bean.Currency;
import com.malex.mxtracker.exception.WrongCommandException;
import com.malex.mxtracker.component.HomePage;
import com.malex.mxtracker.store.EM;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import javax.persistence.EntityManager;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Manusovich Alexander
 */
public class Utils {
    private static Logger logger = LoggerFactory.getLogger(HomePage.class);
    private static final String REPLACEMENT_FOR_SPACE = "_@sb@_";

    public static Map<String, Currency> updateCurrencyDictionary() {
        return updateCurrencyDictionary(null);
    }

    public static Map<String, Currency> updateCurrencyDictionary(final String defCurrency) {
        logger.info("updateCurrencyDictionary - start");
        URL url;
        try {
            /**
             * Читаем последние курсы из сайта НБРБ
             */
            url = new URL("http://www.nbrb.by/Services/XmlExRates.aspx");
            BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
            String line;
            StringBuffer responseData = new StringBuffer();
            while ((line = reader.readLine()) != null) {
                responseData.append(line);
            }
            reader.close();
            /**
             * Парсим XML
             */
            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser saxParser = factory.newSAXParser();
            byte[] buf = responseData.toString().getBytes();
            ByteArrayInputStream stream = new ByteArrayInputStream(buf);
            ArrayList<Currency> list = new ArrayList<Currency>();
            saxParser.parse(stream, new NBRBXMLParser(list));
            /**
             * Удаляем старые курсы
             */
            String def = defCurrency;
            EntityManager em = EM.get().createEntityManager();
            try {
                String query = String.format("select from %s", Currency.class.getName());
                List currencies = em.createQuery(query).getResultList();
                for (Object o : currencies) {
                    Currency c = (Currency) o;
                    if (def == null && (c.getDef() != null && c.getDef())) {
                        def = c.getCharCode();
                    }
                    em.remove(c);
                }
            } finally {
                em.close();
            }
            /**
             * Добавляем родную валюту
             */
            Currency blr = new Currency();
            blr.setCharCode("BLR");
            blr.setRate(1d);
            list.add(blr);
            if (def == null) {
                def = "blr";
            }
            /**
             * Определяем новую валюту по умолчанию и
             * её рейт к белорусскому рублю
             */
            double rate = 0;
            for (Currency c : list) {
                if (def != null && def.equals(c.getCharCode())) {
                    c.setDef(true);
                    rate = c.getRate();
                }
            }
            /**
             * Конвертим все валюты согласно новой по умолчанию
             */
            for (Currency c : list) {
                c.setRate(c.getRate() / rate);
            }
            /**
             * Сохраняем все курсы в базу
             */
            Map<String, Currency> result = new HashMap<String, Currency>();
            for (Currency c : list) {
                em = EM.get().createEntityManager();
                try {
                    em.persist(c);
                    em.refresh(c);
                    result.put(c.getCharCode(), c);
                } finally {
                    em.close();
                }
            }
            return result;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } finally {
            logger.info("updateCurrencyDictionary - end");
        }
        return null;
    }

    public static List<String> getTokens(String command) {
        if (command == null || command.length() == 0) {
            return null;
        }
        List<String> tokens = new ArrayList<String>();
        char first = command.charAt(0);
        if (first == '+' || first == '-') {
            tokens.add(first == '+' ? "add" : "remove");
            command = command.substring(1);
        }
        /**
         * Получаем все строки из комманды 
         */
        Pattern p = Pattern.compile("\"([^\"]+)\"");
        Matcher m = p.matcher(command);
        StringBuffer handledCommand = new StringBuffer();
        while (m.find()) {
            String s = m.group(1);
            m.appendReplacement(handledCommand,
                    s.replaceAll("\\s", REPLACEMENT_FOR_SPACE));
        }
        m.appendTail(handledCommand);

        String cmd = handledCommand.toString();
        for (String t : Arrays.asList(cmd.split("\\s"))) {
            String res = t.replaceAll(REPLACEMENT_FOR_SPACE, " ");
            tokens.add(res.trim());
        }
        return tokens;
    }

    public static Double getDouble(String value) {
        if (value == null || value.length() == 0) {
            value = "0";
        }
        char chDec = new DecimalFormatSymbols().getDecimalSeparator();
        /**
         * Если задали через точку - тогда меняем её на ,
         */
        if (value.indexOf('.') != -1 && '.' != chDec) {
            value = value.replaceAll("\\.", "" + chDec);
        }
        try {
            return Double.valueOf(value);
        } catch (NumberFormatException e) {
            return 0d;
        }
    }

    public static String formatDoubleHTML(final Double value, final String mask) {
        DecimalFormat df1 = new DecimalFormat(mask);
        String sValue = df1.format(value);

        int lastZero = 0;
        for (int i = 0; i < sValue.length(); i++) {
            if (sValue.charAt(i) != '0') {
                lastZero = i - 1;
                break;
            }
        }

        if (lastZero != -1) {
            sValue = "<font color='#eeeeee'>" + sValue.substring(0, lastZero + 1) + "</font>"
                    + sValue.substring(lastZero + 1);
        }

        lastZero = -1;
        for (int i = sValue.length() - 1; i > 0; i--) {
            if (sValue.charAt(i) != '0') {
                lastZero = i + 1;
                break;
            }
        }

        if (lastZero != -1) {
            sValue = sValue.substring(0, lastZero) +
                    "<font color='#eeeeee'>" + sValue.substring(lastZero) + "</font>";
        }
        return sValue;
    }

    /**
     * Получаем количество денег в валюте destination из валюты source в количестве value
     *
     * @param value               Количество денег
     * @param sourceCurrency      Источник - валюта
     * @param destinationCurrency В какой валюте получить
     * @return Результат
     */
    public static Double getMoney(Double value, String sourceCurrency,
                                  String destinationCurrency) throws WrongCommandException {
        Currency source = MxTracker.getCurrencies().get(sourceCurrency);
        Currency destination = MxTracker.getCurrencies().get(destinationCurrency);
        if (source == null) {
            throw new WrongCommandException(
                    String.format("Currency '%s' was not found...", source));
        }
        if (destination == null) {
            throw new WrongCommandException(
                    String.format("Currency '%s' was not found...", destination));
        }
        return source.getRate() / destination.getRate() * value;
    }
}
